import createProps from '../../js/createProps.js' import { dispatchEvent } from '../../js/events.js' import { setCss, makeId } from '../../js/utils.js' import {EVENT_COLLAPSE_TOGGLE, TIME_MEDIUM} from '../../js/constants.js' import breakpoint from '../../js/breakpoints.js' class Collapse extends HTMLElement { constructor() { super() this.classList.add('u-collapse') this.classList.add('animate-click') // Init properties this.label = '' this.heading = 0 this.iconLeft = '' this.iconRight = '24/ui/chevron-bottom' this.collapsible = 'right' // null / left / right / both this.expanded = false this.collapseId = '' this.textClass = 'h-md-regular' this.async = false this.onlyMobile = false // Events this.boundOnClick = this.onClick.bind(this) this.boundOnResize = this.onResize.bind(this) } connectedCallback() { createProps(this, true) this.isHeading = this.heading >=1 && this.heading <= 6 if (this.onlyMobile && !breakpoint.is.mobile) { this.renderNoCollapse() } else { this.setId() this.render() this.setMaxHeight() this.bindEvent() if (this.async) { this.observeSlot() } } } renderNoCollapse() { this.innerHTML = ` ${this.isHeading ? `${this.label}` : `

${this.label}

` } ${this.slot} ` } setId() { if (this.collapseId === '') { this.collapseId = makeId(5) } } render() { this.innerHTML = ` ${this.renderTitle()} ${this.renderPanel()} ` this.button = this.querySelector('button[aria-controls]') this.panel = this.querySelector('div[role="region"]') } renderTitle() { return ` ` } renderIcon(icon, position) { if (icon === '') { return '' } if (this.collapsible === 'both' || this.collapsible === position) { return `` } return `` } renderPanel() { return `
${this.slot}
` } setMaxHeight() { const maxHeight = this.panel.scrollHeight + 1 setCss(this,'--collapse-max-height', maxHeight, true) } toggle() { this.expanded = !this.expanded this.button.setAttribute('aria-expanded', this.expanded) this.panel.setAttribute('aria-hidden', !this.expanded) } close() { // Close method is used by parent accordion, if auto_collapse = true this.expanded = false this.button.setAttribute('aria-expanded', false) this.panel.setAttribute('aria-hidden', true) } onClick(e) { e.preventDefault() this.toggle() this.emit() this.animateClick(e) } emit() { if (this.collapseId) { dispatchEvent({ eventName: EVENT_COLLAPSE_TOGGLE, args: { id: this.collapseId }, element: this.parentElement }) } } animateClick(e) { this.button.classList.add('active') setTimeout(() => { this.button.classList.remove('active') }, TIME_MEDIUM) var rect = e.target.getBoundingClientRect() var x = e.clientX - rect.left //x position within the element. var y = e.clientY - rect.top //y position within the element. this.style.setProperty('--button-mouse-x', x + 'px') this.style.setProperty('--button-mouse-y', y + 'px') } observeSlot() { const self = this const observer = new MutationObserver(mutations => { mutations.forEach(function (mutation) { mutation.addedNodes.forEach(function (added_node) { if (added_node.nodeType === 1) { self.setMaxHeight() // Todo: we need to wait for kgrid to be async fully rendered, when can we disconnect ? // observer.disconnect() } }) }) }) observer.observe(this, { subtree: true, childList: true }) } onResize() { this.setMaxHeight() } bindEvent() { this.unbindEvent() if (this.button) { this.button.addEventListener('click', this.boundOnClick) } window.addEventListener('resize', this.boundOnResize) } unbindEvent() { if (this.button) { this.button.removeEventListener('click', this.boundOnClick) } window.removeEventListener('resize', this.boundOnResize) } disconnectedCallback() { this.unbindEvent() } } customElements.get('u-collapse') || customElements.define('u-collapse', Collapse) export default Collapse